#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2.1).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 2000-05-25 14:41 CDT by <gk4@gnu.austin.ibm.com>.
# Source directory was `/home/gk4/src/groupmem'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#   1960 -rw-r--r-- Makefile
#   6348 -rw-r--r-- groupmems.c
#   3372 -rw------- groupmems.8
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    set `$dir/gettext --version 2>&1`
    if test "$3" = GNU
    then
      gettext_dir=$dir
    fi
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 -a -f $$.touch; then
  shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 -a ! -f 123123592001.5 -a -f $$.touch; then
  shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 -a -f $$.touch; then
  shar_touch='touch -am $3$4$5$6$2 "$8"'
else
  shar_touch=:
  echo
  $echo 'WARNING: not restoring timestamps.  Consider getting and'
  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch
#
if mkdir _sh10937; then
  $echo 'x -' 'creating lock directory'
else
  $echo 'failed to create lock directory'
  exit 1
fi
# ============= Makefile ==============
if test -f 'Makefile' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'Makefile' '(file already exists)'
else
  $echo 'x -' extracting 'Makefile' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
/*
# Copyright 2000, International Business Machines, Inc.
# All rights reserved.
#
# original author: George Kraft IV, gk4@us.ibm.com
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. Neither the name of International Business Machines, Inc., nor the 
#    names of its contributors may be used to endorse or promote products 
#    derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY INTERNATIONAL BUSINESS MACHINES, INC. AND
# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL 
# INTERNATIONAL BUSINESS MACHINES, INC. OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# 
X
all: groupmems
X
groupmems: groupmems.c
X	cc -g -o groupmems groupmems.c -L. -lshadow
X
install: groupmems
X	-/usr/sbin/groupadd groups
X	install -o root -g groups -m 4770 groupmems /usr/bin
X
install.man: groupmems.8
X	install -o root -g root -m 644 groupmems.8 /usr/man/man8
X
SHAR_EOF
  (set 20 00 05 25 14 40 28 'Makefile'; eval "$shar_touch") &&
  chmod 0644 'Makefile' ||
  $echo 'restore of' 'Makefile' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'Makefile:' 'MD5 check failed'
b46cf7ef8d59149093c011ced3f3103c  Makefile
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'Makefile'`"
    test 1960 -eq "$shar_count" ||
    $echo 'Makefile:' 'original size' '1960,' 'current size' "$shar_count!"
  fi
fi
# ============= groupmems.c ==============
if test -f 'groupmems.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'groupmems.c' '(file already exists)'
else
  $echo 'x -' extracting 'groupmems.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'groupmems.c' &&
/*
X * Copyright 2000, International Business Machines, Inc.
X * All rights reserved.
X *
X * original author: George Kraft IV, gk4@us.ibm.com
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X *
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. Neither the name of International Business Machines, Inc., nor the 
X *    names of its contributors may be used to endorse or promote products 
X *    derived from this software without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY INTERNATIONAL BUSINESS MACHINES, INC. AND
X * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
X * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
X * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL 
X * INTERNATIONAL BUSINESS MACHINES, INC. OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X */
/*
**
**	Utility "groupmem" adds and deletes members from a user's group.
**	
**	Setup (as "root"):
**	
**		groupadd -r groups 
**		chmod 2770 groupmems
**		chown root.groups groupmems
**		groupmems -g groups -a gk4
**	
**	Usage (as "gk4"):
**	
**		groupmems -a olive
**		groupmems -a jordan
**		groupmems -a meghan
**		groupmems -a morgan
**		groupmems -a jake
**		groupmems -l 
**		groupmems -d jake
**		groupmems -l 
*/
X
#include <stdio.h>
#include <pwd.h>
#include <grp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "defines.h"
#include "groupio.h"
X
/* Exit Status Values */
X
#define EXIT_SUCCESS		0	/* success */
#define EXIT_USAGE		1	/* invalid command syntax */
#define EXIT_GROUP_FILE		2	/* group file access problems */
#define EXIT_NOT_ROOT		3	/* not superuser  */
#define EXIT_NOT_EROOT		4	/* not effective superuser  */
#define EXIT_NOT_PRIMARY	5	/* not primary owner of group  */
#define EXIT_NOT_MEMBER		6	/* member of group does not exist */
#define EXIT_MEMBER_EXISTS	7	/* member of group already exists */
X
#define TRUE 1
#define FALSE 0
X
/* Globals */
X
extern int optind;
extern char *optarg;
static char *adduser = NULL;
static char *deluser = NULL;
static char *thisgroup = NULL;
static int purge = FALSE;
static int list = FALSE;
static int exclusive = 0;
X
static int isroot(void) {
X	return getuid() ? FALSE : TRUE;
}
X
static int isgroup(void) {
X	gid_t g = getgid();
X	struct group *grp = getgrgid(g);
X
X	return TRUE;
}
X
static char *whoami(void) {
X	struct group *grp = getgrgid(getgid());
X	struct passwd *usr = getpwuid(getuid());
X
X	if (0 == strcmp(usr->pw_name, grp->gr_name)) {
X		return (char *)strdup(usr->pw_name);
X	} else {
X		return NULL;
X	} 
}
X
static void
addtogroup(char *user, char **members) {
X	int i;
X	char **pmembers;
X
X	for (i = 0; NULL != members[i]; i++ ) {
X		if (0 == strcmp(user, members[i])) {
X			fprintf(stderr, "Member already exists\n");
X			exit(EXIT_MEMBER_EXISTS);
X		}
X	}
X
X	if (0 == i) {
X		pmembers = (char **)calloc(2, sizeof(char *));
X	} else {
X		pmembers = (char **)realloc(members, sizeof(char *)*(i+1));
X	}
X
X	*members = *pmembers;
X	members[i] = user;
X	members[i+1] = NULL;
}
X
static void
rmfromgroup(char *user, char **members) {
X	int i;
X	int found = FALSE;
X
X	i = 0;
X	while (!found && NULL != members[i]) {
X		if (0 == strcmp(user, members[i])) {
X			found = TRUE;
X		} else {
X			i++;
X		}
X	}
X
X	while (found && NULL != members[i]) {
X		members[i] = members[++i];
X	}
X
X	if (!found) {
X		fprintf(stderr, "Member to remove could not be found\n");
X		exit(EXIT_NOT_MEMBER);
X	}
}
X
static void
nomembers(char **members) {
X	int i;
X
X	for (i = 0; NULL != members[i]; i++ ) {
X		members[i] = NULL;
X	}
}
X
static void
members(char **members) {
X	int i;
X
X	for (i = 0; NULL != members[i]; i++ ) {
X		printf("%s ", members[i]);
X
X		if (NULL == members[i+1]) {
X			printf("\n");
X		} else {
X			printf(" ");
X		}
X	}
}
X
static void usage(void) {
X	fprintf(stderr, "usage: groupmems -a username | -d username | -D | -l [-g groupname]\n");
X	exit(EXIT_USAGE);
}
X
main(int argc, char **argv) {
X	int arg, i;
X	char *name;
X	struct group *grp;
X
X	while ((arg = getopt(argc, argv, "a:d:g:Dl")) != EOF) {
X		switch (arg) {
X		case 'a':
X			adduser = strdup(optarg);
X			++exclusive;
X			break;
X		case 'd':
X			deluser = strdup(optarg);
X			++exclusive;
X			break;
X		case 'g':
X			thisgroup = strdup(optarg);
X			break;
X		case 'D':
X			purge = TRUE;
X			++exclusive;
X			break;
X		case 'l':
X			list = TRUE;
X			++exclusive;
X			break;
X		default:
X			usage();
X		}
X	}
X
X	if (exclusive > 1 || optind < argc) {
X		usage();
X	}
X
X	if (!isroot() && NULL != thisgroup) {
X		fprintf(stderr, "Only root can add members to different groups\n");
X		exit(EXIT_NOT_ROOT);
X	} else if (isroot() && NULL != thisgroup) {
X		name = thisgroup;
X	} else if (!isgroup()) {
X		fprintf(stderr, "Group access is required\n");
X		exit(EXIT_NOT_EROOT);
X	} else if (NULL == (name = whoami())) {
X		fprintf(stderr, "Not primary owner of current group\n");
X		exit(EXIT_NOT_PRIMARY);
X	}
X
X	if (!gr_lock()) {
X		fprintf(stderr, "Unable to lock group file\n");
X		exit(EXIT_GROUP_FILE);
X	}
X
X	if (!gr_open(O_RDWR)) {
X		fprintf(stderr, "Unable to open group file\n");
X		exit(EXIT_GROUP_FILE);
X	}
X
X	grp = (struct group *)gr_locate(name);
X
X	if (NULL != adduser) {
X		addtogroup(adduser, grp->gr_mem);
X		gr_update(grp);
X	} else if (NULL != deluser) {
X		rmfromgroup(deluser, grp->gr_mem);
X		gr_update(grp);
X	} else if (purge) {
X		nomembers(grp->gr_mem);
X		gr_update(grp);
X	} else if (list) {
X		members(grp->gr_mem);
X	}
X
X	if (!gr_close()) {
X		fprintf(stderr, "Cannot close group file\n");
X		exit(EXIT_GROUP_FILE);
X	}
X
X	gr_unlock();
X
X	exit(EXIT_SUCCESS);
}
X
/* EOF */
SHAR_EOF
  (set 20 00 05 25 14 36 38 'groupmems.c'; eval "$shar_touch") &&
  chmod 0644 'groupmems.c' ||
  $echo 'restore of' 'groupmems.c' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'groupmems.c:' 'MD5 check failed'
f0dd68f8d762d89d24d3ce1f4141f981  groupmems.c
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'groupmems.c'`"
    test 6348 -eq "$shar_count" ||
    $echo 'groupmems.c:' 'original size' '6348,' 'current size' "$shar_count!"
  fi
fi
# ============= groupmems.8 ==============
if test -f 'groupmems.8' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'groupmems.8' '(file already exists)'
else
  $echo 'x -' extracting 'groupmems.8' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'groupmems.8' &&
X.\"
X.\" Copyright 2000, International Business Machines, Inc.
X.\" All rights reserved.
X.\"
X.\" original author: George Kraft IV, gk4@us.ibm.com
X.\"
X.\" Redistribution and use in source and binary forms, with or without
X.\" modification, are permitted provided that the following conditions
X.\" are met:
X.\"
X.\" 1. Redistributions of source code must retain the above copyright
X.\"    notice, this list of conditions and the following disclaimer.
X.\" 2. Redistributions in binary form must reproduce the above copyright
X.\"    notice, this list of conditions and the following disclaimer in the
X.\"    documentation and/or other materials provided with the distribution.
X.\" 3. Neither the name of International Business Machines, Inc., nor the 
X.\"    names of its contributors may be used to endorse or promote products 
X.\"    derived from this software without specific prior written permission.
X.\"
X.\" THIS SOFTWARE IS PROVIDED BY INTERNATIONAL BUSINESS MACHINES, INC. AND
X.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
X.\" BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
X.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL 
X.\" INTERNATIONAL BUSINESS MACHINES, INC. OR CONTRIBUTORS BE LIABLE
X.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X.\" SUCH DAMAGE.
X.\"
X.\" $Id$
X.\"
X.TH GROUPMEMS 8
X.SH NAME
groupmems \- Administer members of a user's primary group
X.SH SYNOPSIS
X.B groupmems
\fB-a\fI user_name \fR |
\fB-d\fI user_name \fR |
\fB-l\fR |
\fB-D\fR |
[\fB-g\fI group_name \fR]
X.SH DESCRIPTION
The \fBgroupmems\fR utility allows a user to administer their own
group membership list without the requirement of superuser privileges.
The \fBgroupmems\fR utility is for systems that configure its users to
be in their own name sake primary group (i.e., guest / guest).
X.P
Only the superuser, as administrator, can use \fBgroupmems\fR to alter
the memberships of other groups.
X.IP "\fB-a \fIuser_name\fR"
Add a new user to the group membership list.
X.IP "\fB-d \fIuser_name\fR"
Delete a user from the group membership list.
X.IP "\fB-l\fR"
List the group membership list.
X.IP "\fB-D\fR"
Delete all users from the group membership list.
X.IP "\fB-g \fIgroup_name\fR"
The superuser can specify which group membership list to modify.
X.SH SETUP
The \fBgroupmems\fR executable should be in mode \fB2770\fR as user \fBroot\fR
and in group \fBgroups\fR.   The system administrator can add users to
group groups to allow or disallow them using the  \fBgroupmems\fR utility
to manager their own group membership list.
X.P
X     $ groupadd -r groups
X.br
X     $ chmod 2770 groupmems
X.br
X     $ chown root.groups groupmems
X.br
X     $ groupmems -g groups -a gk4
X.SH FILES
/etc/group
X.br
/etc/gshadow
X.SH SEE ALSO
X.BR chfn (1),
X.BR chsh (1),
X.BR useradd (8),
X.BR userdel (8),
X.BR usermod (8),
X.BR passwd (1),
X.BR groupadd (8),
X.BR groupdel (8)
X.SH AUTHOR
George Kraft IV (gk4@us.ibm.com)
X.\" EOF
SHAR_EOF
  (set 20 00 05 25 14 38 23 'groupmems.8'; eval "$shar_touch") &&
  chmod 0600 'groupmems.8' ||
  $echo 'restore of' 'groupmems.8' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'groupmems.8:' 'MD5 check failed'
181e6cd3a3c9d3df320197fa2cde2b4a  groupmems.8
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'groupmems.8'`"
    test 3372 -eq "$shar_count" ||
    $echo 'groupmems.8:' 'original size' '3372,' 'current size' "$shar_count!"
  fi
fi
rm -fr _sh10937
exit 0
